import { defineComponent, ref, watch } from "vue";
import { Upload, Button } from "ant-design-vue";
import type {
	UploadProps,
	FileType,
	UploadFile,
} from "ant-design-vue/lib/upload/interface";

type InputFileType = keyof typeof fileTypeMapsToMediaTypes;
type BeforeUploadFunc = UploadProps["beforeUpload"];
type ValidateType = {
	fileValidateErrorMessage: string;
	fileName: string;
	uid: string;
};

type ValidateChecker = (
	file: FileType
) => ValidateType | Promise<ValidateType> | null;

interface IProps extends Omit<UploadProps, "accept"> {
	uploadFileList: (UploadFile & { [cacheFileStatuskey]: any })[];
	fileType?: InputFileType | InputFileType[];

	/**
	 * 传入的具体大小
	 *  比如 10 -> 10M 50 -> 50M
	 */
	fileSize?: number;
	ratio?: {
		width: number;
		height: number;
	};
}

const cacheFileStatuskey = Symbol("responseStatus");

let localImageNode: HTMLImageElement | null = null;
let localFileReader: FileReader | null = null;

const fileTypeMapsToMediaTypes = {
	image: "image/*",
	png: ".png",
	jpg: ".jpg, .jpeg",

	video: "video/*",
	audio: "audio/*",

	json: "application/json",

	js: "application/javascript",
	css: "text/css",
	html: "text/html",

	doc: "application/vnd.openxmlformats",
};

function asyncUploadFile(file: File) {
	const fd = new FormData();
	fd.append("file", file);
}

const UploadFileComponent = defineComponent<IProps>((props, ctx) => {
	const fileType = props.fileType;
	const fileAccept =
		typeof fileType === "undefined"
			? "*"
			: Array.isArray(fileType)
			? fileType.map((type2) => fileTypeMapsToMediaTypes[type2]).join(",")
			: fileType;

	const beforeUpload = props.beforeUpload;
	const customRequest = props.customRequest;

	const fileSize = props.fileSize ?? 2;
	const ratio = props.ratio;

	const uploadFileList = ref(
		Array.isArray(props.uploadFileList) ? [...props.uploadFileList] : []
	);

	watch(
		() => uploadFileList.value,
		() => {
			ctx.emit("update:uploadFileList", uploadFileList.value);
		}
	);

	const validateChain: ValidateChecker[] = [];

	if (typeof fileSize === "number") {
		const validateFileSize = function validateFileSize(file: FileType) {
			const size = file.size / 1024 / 1024;
			if (size > fileSize) {
				return Promise.reject({
					fileValidateErrorMessage: "文件大小超过" + fileSize,
					fileName: file.name,
					uid: file.uid,
				});
			}
			return null;
		};
		validateChain.push(validateFileSize);
	}

	if (
		typeof ratio !== "undefined" &&
		!/(jpg|png|image)/.test(fileType.toString())
	) {
		const validateRatio = function validateFileSize(
			file: FileType
		): Promise<ValidateType | null> {
			if (localFileReader === null) {
				localFileReader = new FileReader();
			}
			if (localImageNode === null) {
				localImageNode = document.createElement("img");
			}

			return new Promise((resolve, reject) => {
				localFileReader.onload = function () {
					localImageNode.onload = function () {
						const imageWidth = localImageNode.width,
							imageHeight = localImageNode.height;

						if (ratio.height < imageHeight || ratio.width < imageWidth) {
							reject({
								uid: file.uid,
								fileValidateErrorMessage: `图片分辨率大于 ${ratio.height} * ${ratio.width}`,
								fileName: file.name,
							});
							return;
						}
						resolve(null);
						localImageNode = localFileReader.onload = null;
					};
					localImageNode.src = localFileReader.result as string;
				};

				localFileReader.readAsDataURL(file);
			});
		};

		validateChain.push(validateRatio);
	}

	let dynamicFileMessage = null;
	let currentFile = null;

	const uploadFileBeforeUpload = async function uploadFileBeforeUpload(
		file: FileType,
		fileList: FileType[]
	) {
		try {
			await Promise.all(validateChain.map((fn) => fn(file)));
		} catch (exx) {
			if (
				typeof exx.fileValidateErrorMessage === "string" &&
				typeof exx.fileName === "string"
			) {
				// dynamicFileMessage.push(exx);
				dynamicFileMessage = exx;
			}
			return Promise.reject(false);
		}

		const rs = await beforeUpload?.(file, fileList);

		return rs ?? true;
	} as BeforeUploadFunc;

	const listenofFileSelectChange: UploadProps["onChange"] = (info) => {
		const file = (currentFile = info.file);

		if (dynamicFileMessage === null) {
			file.status = "uploading";
			uploadFileList.value.push(file as any);
			return;
		}

		const findFile = uploadFileList.value.find(
			(exist) => dynamicFileMessage.uid === exist.uid
		);
		if (typeof findFile === "undefined") {
			file.status = "error";
			uploadFileList.value.push(file as any);
			currentFile = dynamicFileMessage = null;
		}
	};

	const uploadCustomRequest = (fileInfo) => {
		if (typeof customRequest === "function") {
			customRequest(fileInfo);
			return;
		}

		if (currentFile === null) {
			return;
		}
		const findFile = uploadFileList.value.find(
			(exist) => currentFile.uid === exist.uid
		);

		asyncUploadFile(fileInfo.file)
			.then((rs) => {
				findFile[cacheFileStatuskey] = rs;
				findFile.status = "success";
			})
			.catch(() => {
				findFile.status = "error";
			});
	};

	const deletingForExistFile = (fileInfo) => {};

	return () => {
		return (
			<Upload
				accept={fileAccept}
				onRemove={deletingForExistFile}
				fileList={uploadFileList.value}
				beforeUpload={uploadFileBeforeUpload}
				onChange={listenofFileSelectChange}
				customRequest={uploadCustomRequest}
			>
				<Button>上传文件</Button>
			</Upload>
		);
	};
});

UploadFileComponent.props = ["fileType", "uploadFileList", "fileSize", "ratio"];
UploadFileComponent.emits = ["update:uploadFileList"];
export default UploadFileComponent;
